home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / nos042_s / hop.c < prev    next >
C/C++ Source or Header  |  1994-09-16  |  11KB  |  425 lines

  1. /*
  2.  *    HOP.C   -- trace route packets take to a remote host
  3.  *
  4.  *    02-90    -- Katie Stevens (dkstevens@ucdavis.edu)
  5.  *           UC Davis, Computing Services
  6.  *           Davis, CA
  7.  *    04-90    -- Modified by Phil Karn to use raw IP sockets to read replies
  8.  *    08-90    -- Modified by Bill Simpson to display domain names
  9.  *
  10.  * ATARI Version by David Nash - dnash@chaos.demon.co.uk
  11.  *
  12.  * __stdargs hopcheck, ANSI function defn hopcheck, geticmp   
  13.  */
  14.  
  15. /****************************************************************************
  16. *    $Id: hop.c 1.2 93/07/16 11:45:09 ROOT_DOS Exp $
  17. *    08 May 93    1.2        GT    Fix warnings.                                    *
  18. ****************************************************************************/
  19.  
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include "global.h"
  23. #include "mbuf.h"
  24. #include "usock.h"
  25. #include "socket.h"
  26. #include "session.h"
  27. #include "timer.h"
  28. #include "proc.h"
  29. #include "netuser.h"
  30. #include "domain.h"
  31. #include "commands.h"
  32. #include "tty.h"
  33. #include "cmdparse.h"
  34. #include "ip.h"
  35. #include "icmp.h"
  36. #include "udp.h"
  37. #include "hardware.h"
  38.  
  39. #define HOPMAXQUERY    5        /* Max# queries each TTL value */
  40. static int16 Hoprport = (int16) (32768L+666);    /* funny port for udp probes */
  41. #define HOP_HIGHBIT    32768        /* Mask to check ICMP msgs */
  42.  
  43.  
  44. #define HOPTRACE    1        /* Enable HOP tracing */
  45. #ifdef HOPTRACE
  46. static int Hoptrace = 0;
  47. static int hoptrace __ARGS((int argc,char *argv[],void *p));
  48. #endif
  49.  
  50.  
  51. static unsigned  short Hopmaxttl  = 30;        /* max attempts */
  52. static unsigned  short Hopmaxwait = 5;        /* secs timeout each attempt */
  53. static unsigned  short Hopquery   = 3;        /* #probes each attempt */
  54.  
  55. static int __stdargs hopcheck __ARGS((int argc,char *argv[],void *p));
  56. static int hopttl __ARGS((int argc,char *argv[],void *p));
  57. static int hopwait __ARGS((int argc,char *argv[],void *p));
  58. static int hopnum __ARGS((int argc,char *argv[],void *p));
  59. static int geticmp __ARGS((int s,int16 lport,int16 fport,
  60.     int32 *sender,char *type,char *code));
  61.  
  62. static struct cmds Hopcmds[] = {
  63.     { "check",    hopcheck,    2048,    2,    "check <host>" },
  64.     { "maxttl",    hopttl,        0,    0,    NULLCHAR },
  65.     { "maxwait",    hopwait,    0,    0,    NULLCHAR },
  66.     { "queries",    hopnum,        0,    0,    NULLCHAR },
  67. #ifdef HOPTRACE
  68.     { "trace",    hoptrace,    0,    0,    NULLCHAR },
  69. #endif
  70.     { NULLCHAR },
  71. };
  72.  
  73. /* attempt to trace route to a remote host */
  74. int
  75. dohop(argc,argv,p)
  76. int argc;
  77. char *argv[];
  78. void *p;
  79. {
  80.     return subcmd(Hopcmds,argc,argv,p);
  81. }
  82.  
  83. /* Set/show # queries sent each TTL value */
  84. static int
  85. hopnum(argc,argv,p)
  86. int argc;
  87. char *argv[];
  88. void *p;
  89. {
  90.     int16 r;
  91.     int16 x = Hopquery;
  92.     r = setshort(&x,"# queries each attempt",argc,argv);
  93.     if ((x <= 0)||(x > HOPMAXQUERY)) {
  94.         printf("Must be  0 < x <= %d\n",HOPMAXQUERY);
  95.         return 0;
  96.     } else {
  97.         Hopquery = x;
  98.     }
  99.     return (int)r;
  100. }
  101. #ifdef HOPTRACE
  102. /* Set/show tracelevel */
  103. static int
  104. hoptrace(argc,argv,p)
  105. int argc;
  106. char *argv[];
  107. void *p;
  108. {
  109.     return setbool(&Hoptrace,"HOPCHECK tracing",argc,argv);
  110. }
  111. #endif
  112. /* Set/show maximum TTL value for a traceroute query */
  113. static int
  114. hopttl(argc,argv,p)
  115. int argc;
  116. char *argv[];
  117. void *p;
  118. {
  119.     int16 r;
  120.     int16 x = Hopmaxttl;
  121.     r = setshort(&x,"Max attempts to reach host",argc,argv);
  122.     if ((x <= 0)||(x > 255)) {
  123.         printf("Must be  0 < x <= 255\n");
  124.         return 0;
  125.     } else {
  126.         Hopmaxttl = x;
  127.     }
  128.     return (int)r;
  129. }
  130. /* Set/show #secs until timeout for a traceroute query */
  131. static int
  132. hopwait(argc,argv,p)
  133. int argc;
  134. char *argv[];
  135. void *p;
  136. {
  137.     int16 r;
  138.     int16 x = Hopmaxwait;
  139.     r = setshort(&x,"# secs to wait for reply to query",argc,argv);
  140.     if (x <= 0) {
  141.         printf("Must be >= 0\n");
  142.         return 0;
  143.     } else {
  144.         Hopmaxwait = x;
  145.     }
  146.     return (int)r;
  147. }
  148.  
  149. /* send probes to trace route of a remote host */
  150. static int __stdargs hopcheck(
  151.     int argc,
  152.     char *argv[],
  153.     void *p )
  154. {
  155.     struct session *sp;        /* Session for trace output */
  156.     int s;                /* Socket for queries */
  157.     int s1;                /* Raw socket for replies */
  158.     struct socket lsocket;        /* Local socket sending queries */
  159.     struct socket rsocket;        /* Final destination of queries */
  160.     int32 cticks;            /* Timer for query replies */
  161.     int32 icsource;            /* Sender of last ICMP reply */
  162.     char ictype;            /* ICMP type last ICMP reply */
  163.     char iccode;            /* ICMP code last ICMP reply */
  164.     int32 lastaddr;            /* Sender of previous ICMP reply */
  165.     struct sockaddr_in sock;
  166.     register struct usock *usp;
  167.     register struct sockaddr_in *sinp;
  168.     unsigned char sndttl, q;
  169.     int tracedone = 0;
  170.     int ilookup = 1;        /* Control of inverse domain lookup */
  171.     int c;
  172.     extern int optind;
  173.     char *hostname;
  174.     int save_trace;
  175.  
  176.     optind = 1;
  177.     while((c = getopt(argc,argv,"n")) != EOF){
  178.         switch(c){
  179.         case 'n':
  180.             ilookup = 0;
  181.             break;
  182.         }
  183.     }
  184.     hostname = argv[optind];
  185.     /* Allocate a session descriptor */
  186.     if((sp = newsession(hostname,HOP)) == NULLSESSION){
  187.         tprintf("Too many sessions\n");
  188.         keywait(NULLCHAR,1);
  189.         return 1;
  190.     }
  191.     sp->s = s = -1;
  192.     sp->flowmode = 1;
  193.  
  194.     /* Setup UDP socket to remote host */
  195.     sock.sin_family = AF_INET;
  196.     sock.sin_port = Hoprport;
  197.     tprintf("Resolving %s... ",hostname);
  198.     if((sock.sin_addr.s_addr = resolve(hostname)) == 0){
  199.         tprintf("Host %s unknown\n",hostname);
  200.         keywait(NULLCHAR,1);
  201.         freesession(sp);
  202.         return 1;
  203.     }
  204.  
  205.     /* Open socket to remote host */
  206.     tprintf("traceroute to %s\n",psocket((struct sockaddr *)&sock));
  207.     if((sp->s = s = socket(AF_INET,SOCK_DGRAM,0)) == -1){
  208.         tprintf("Can't create udp socket\n");
  209.         keywait(NULLCHAR,1);
  210.         freesession(sp);
  211.         return 1;
  212.     }
  213.     if(connect(s,(char *)&sock,sizeof(sock)) == -1){
  214.         tprintf("Connect failed\n");
  215.         keywait(NULLCHAR,1);
  216.         freesession(sp);
  217.         return 1;
  218.     }
  219.     if((s1 = socket(AF_INET,SOCK_RAW,ICMP_PTCL)) == -1){
  220.         tprintf("Can't create raw socket\n");
  221.         keywait(NULLCHAR,1);
  222.         freesession(sp);
  223.         return 1;
  224.     }
  225.     /* turn off icmp tracing while hop-checking */
  226.     save_trace = Icmp_trace;
  227.     Icmp_trace = 0;
  228.  
  229.     /* Setup structures to send queries */
  230.     /* Retrieve socket details for user socket control block */
  231.     usp = itop(s);
  232.     sinp = (struct sockaddr_in *)usp->name;
  233.     lsocket.address = sinp->sin_addr.s_addr;
  234.     lsocket.port = sinp->sin_port;
  235.     sinp = (struct sockaddr_in *)usp->peername;
  236.     rsocket.address = sinp->sin_addr.s_addr;
  237.  
  238.     /* Send queries with increasing TTL; start with TTL=1 */
  239.     if (Hoptrace)
  240.         log(sp->s,"HOPCHECK start trace to %s\n",sp->name);
  241.     for (sndttl=1; (sndttl < Hopmaxttl); ++sndttl, sinp->sin_port++) {
  242.         /* Increment funny UDP port number each round */
  243.         rsocket.port = sinp->sin_port;
  244.         tprintf("%3d:",sndttl);
  245.         lastaddr = (int32)0;
  246.         /* Send a round of queries */
  247.         for (q=0; (q < Hopquery); ++q) {
  248.             send_udp(&lsocket,&rsocket,0,sndttl,NULLBUF,0,0,0);
  249.             cticks = msclock();
  250.             alarm( ((long)Hopmaxwait*1000L) );
  251.  
  252.             /* Wait for a reply to our query */
  253.             if(geticmp(s1,lsocket.port,rsocket.port,
  254.              &icsource,&ictype,&iccode) == -1){
  255.                 if(errno != EALARM)
  256.                     goto done;    /* User reset */
  257.                 /* Alarm rang, give up waiting for replies */
  258.                 tprintf(" ***");
  259.                 continue;
  260.             }
  261.             /* Save #ticks taken for reply */
  262.                         cticks = msclock() - cticks;
  263.             /* Report ICMP reply */
  264.             if (icsource != lastaddr) {
  265.                 struct rr *save_rrlp, *rrlp;
  266.  
  267.                 if(lastaddr != (int32)0)
  268.                     tprintf("\n    ");
  269.                 tprintf(" %-15s",inet_ntoa(icsource));
  270.                 if(ilookup){
  271.                     for(rrlp = save_rrlp = inverse_a(icsource);
  272.                         rrlp != NULLRR;
  273.                         rrlp = rrlp->next){
  274.                         if(rrlp->rdlength > 0){
  275.                             switch(rrlp->type){
  276.                             case TYPE_PTR:
  277.                                 tprintf(" %s", rrlp->rdata.name);
  278.                                 break;
  279.                             case TYPE_A:
  280.                                 tprintf(" %s", rrlp->name);
  281.                                 break;
  282.                             }
  283.                             if(rrlp->next != NULLRR)
  284.                                 tprintf("\n%20s"," ");
  285.                         }
  286.                     }
  287.                     free_rr(save_rrlp);
  288.  
  289.                 }
  290.                 lastaddr = icsource;
  291.             }
  292.                         tprintf(" (%ld ms)",cticks);
  293. #ifdef HOPTRACE
  294.             if (Hoptrace)
  295.                 log(sp->s,
  296.                     "(hopcheck) ICMP from %s (%ldms) %s %s",
  297.                     inet_ntoa(icsource),
  298.                     cticks,
  299.                     Icmptypes[ictype],
  300.                     ((ictype == ICMP_TIME_EXCEED)?Exceed[iccode]:Unreach[iccode]));
  301. #endif
  302.  
  303.             /* Check type of reply */
  304.             if (ictype == ICMP_TIME_EXCEED)
  305.                 continue;
  306.             /* Reply was: destination unreachable */
  307.             switch(iccode) {
  308.             case ICMP_PORT_UNREACH:
  309.                 ++tracedone;
  310.                 break;
  311.             case ICMP_NET_UNREACH:
  312.                 ++tracedone;
  313.                 tprintf(" !N");
  314.                 break;
  315.             case ICMP_HOST_UNREACH:
  316.                 ++tracedone;
  317.                 tprintf(" !H");
  318.                 break;
  319.             case ICMP_PROT_UNREACH:
  320.                 ++tracedone;
  321.                 tprintf(" !P");
  322.                 break;
  323.             case ICMP_FRAG_NEEDED:
  324.                 ++tracedone;
  325.                 tprintf(" !F");
  326.                 break;
  327.             case ICMP_ROUTE_FAIL:
  328.                 ++tracedone;
  329.                 tprintf(" !S");
  330.                 break;
  331.                         case ICMP_ADMIN_PROHIB:
  332.                                 ++tracedone;
  333.                                 tprintf(" !A");
  334.                                 break;
  335.                         default:
  336.                                 tprintf(" !?");
  337.                                 break;
  338.             }
  339.         }
  340.         /* Done with this round of queries */
  341.         alarm((long)0);
  342.         tprintf("\n");
  343.         /* Check if we reached remote host this round */
  344.         if (tracedone != 0)
  345.             break;
  346.     }
  347.  
  348.     /* Done with traceroute */
  349. done:    close_s(s);
  350.     sp->s = -1;
  351.     close_s(s1);
  352.     tprintf("traceroute done: ");
  353.     Icmp_trace = save_trace;
  354.     if (sndttl >= Hopmaxttl) {
  355.         tprintf("!! maximum TTL exceeded\n");
  356.     } else if ((icsource == rsocket.address)
  357.             &&(iccode == ICMP_PORT_UNREACH)) {
  358.         tprintf("normal (%s %s)\n",
  359.             Icmptypes[ictype],Unreach[iccode]);
  360.     } else {
  361.         tprintf("!! %s %s\n",
  362.             Icmptypes[ictype],Unreach[iccode]);
  363.     }
  364. #ifdef HOPTRACE
  365.     if (Hoptrace)
  366.         log(sp->s,"HOPCHECK to %s done",sp->name);
  367. #endif
  368.     keywait(NULLCHAR,1);
  369.     freesession(sp);
  370.     return 0;
  371. }
  372.  
  373. /* Read raw network socket looking for ICMP messages in response to our
  374.  * UDP probes
  375.  */
  376.  
  377. static int geticmp(
  378.     int s,
  379.     int16 lport,
  380.     int16 fport,
  381.     int32 *sender,
  382.     char *type,
  383.     char *code)
  384. {
  385.     int size;
  386.     struct icmp icmphdr;
  387.     struct ip iphdr;
  388.     struct udp udphdr;
  389.     struct mbuf *bp;
  390.     struct sockaddr_in sock;
  391.  
  392.     for(;;){
  393.         size = sizeof(sock);
  394.         if(recv_mbuf(s,&bp,0,(char *)&sock,&size) == -1)
  395.             return -1;
  396.         /* It's an ICMP message, let's see if it's interesting */
  397.         ntohicmp(&icmphdr,&bp);
  398.         if((icmphdr.type != ICMP_TIME_EXCEED ||
  399.          icmphdr.code != ICMP_TTL_EXCEED)
  400.          && icmphdr.type != ICMP_DEST_UNREACH){
  401.             /* We're not interested in these */
  402.             free_p(bp);
  403.             continue;
  404.         }
  405.         ntohip(&iphdr,&bp);
  406.         if(iphdr.protocol != UDP_PTCL){
  407.             /* Not UDP, so can't be interesting */
  408.             free_p(bp);
  409.             continue;
  410.         }
  411.         ntohudp(&udphdr,&bp);
  412.         if(udphdr.dest != fport || udphdr.source != lport){
  413.             /* Not from our hopcheck session */
  414.             free_p(bp);
  415.             continue;
  416.         }
  417.         /* Passed all of our checks, so return it */
  418.         *sender = sock.sin_addr.s_addr;
  419.         *type = icmphdr.type;
  420.         *code = icmphdr.code;
  421.         free_p(bp);
  422.         return 0;
  423.     }
  424. }
  425.